using System;
using System.Data;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Collections.Generic;
using System.Text.RegularExpressions;

/// <summary>
/// Summary description for CheckBoxListOther
/// </summary>
public class CheckBoxListOther : DataBoundControl, ICheckBoxListOther
{
    //protected ob dsSource;

    protected string sOtherCheckboxText = "Others";
    protected string sOtherTextPrompt = "Other:";

    protected string sKeyField = "Value";
    protected string sItemField = "Value";

    /// <summary>
    /// The column name from the data source to be used as the key for
    /// the generated comboBoxes. Values from this column must be unique
    /// </summary>
    public string KeyField
    {
        get { return sKeyField; }
        set { sKeyField = value; }
    }

    /// <summary>
    /// The column name from the data source to be used as the text for
    /// the generated comboBoxes. 
    /// </summary>
    public string ItemField
    {
        get { return sItemField; }
        set { sItemField = value; }
    }

    /// <summary>
    /// The text to be displayed on the additional combobox that specifies Other data
    /// </summary>
    public string OtherCheckboxText
    {
        get { return sOtherCheckboxText; }
        set { sOtherCheckboxText = value; }
    }

    /// <summary>
    /// The text to be displayed above the textbox where the user may input Other data
    /// </summary>
    public string OtherPrompt
    {
        get { return sOtherTextPrompt; }
        set { sOtherTextPrompt = value; }
    }

    public string OtherText
    {
        get { return txtOtherText.Text; }
        set { txtOtherText.Text = value; }
    }


    protected object datasource;
    public override object DataSource { get { return datasource; } set { datasource = value; } }

    private string textfield, valuefield;

    public string DataTextField { get { return textfield; } set { textfield = value; } }
    public string DataValueField { get { return valuefield; } set { valuefield = value; } }

    public ListItemCollection SelectedItems
    {
        get
        {
            ListItemCollection lic = new ListItemCollection();

            foreach (string key in cbxList.Keys)
            {

                if (cbxList[key].Checked)
                {
                    ListItem li = new ListItem();
                    if (key == "Others")
                    {
                        li.Text = txtOtherText.Text;
                    }
                    else
                    {
                        li.Text = cbxList[key].Text;
                    }
                    li.Value = key;
                    lic.Add(li);
                }
            }

            return lic;
        }
    }

    protected override void OnPreRender(EventArgs e)
    {
        base.OnPreRender(e);

    }

    protected override void CreateChildControls()
    {
        Controls.Clear();

        if (ViewState["CheckBoxListOtherData"] != null)
            CreateControlHierarchy(false);

        base.CreateChildControls();
    }


    protected override void LoadViewState(object savedState)
    {
        if (savedState != null)
        {
            object[] allStates = (object[])savedState;
            base.LoadViewState(allStates[0]);
            //txtOtherText.Text = allStates[2];
        }
    }

    protected override object SaveViewState()
    {
        object[] allStates = new object[3];
        object[] selKey = new object[SelectedItems.Count];
        int i = 0;
        foreach (ListItem li in SelectedItems)
        {
            selKey[i++] = li.Value;
        }
        allStates[0] = base.SaveViewState();
        allStates[1] = selKey;
        allStates[2] = txtOtherText.Text;
        return allStates;
    }

    public override void DataBind()
    {
        base.OnDataBinding(EventArgs.Empty);
        //dsSource = (DataSet)datasource;
        // Create the control hierarchy.  First, clear out the child controls
        Controls.Clear();
        ClearChildViewState();
        TrackViewState();

        // Create the control hierarchy
        CreateControlHierarchy(true);

        // Mark the hierarchy as having been created
        ChildControlsCreated = true;
    }


    protected Dictionary<string, CheckBox> cbxList = new Dictionary<string, CheckBox>();

    protected TextBox txtOtherText = new TextBox();
    TableRow tblOtherRow;

    public CheckBoxListOther()
    {
    }

    /// <summary>
    /// Set the datasource to be used as a basis for the list
    /// </summary>
    /// <param name="source"></param>
    public CheckBoxListOther(DataSet source)
    {
        datasource = source.Tables[0];
    }

    #region " ICheckBoxListOther methods "

    void ICheckBoxListOther.LoadData(DataTable data, string KeyField, string OtherField)
    {
        this.LoadData(data, KeyField, OtherField);
    }

    DataTable ICheckBoxListOther.GetData()
    {
        return this.GetData();
    }

    void ICheckBoxListOther.Clear()
    {
        this.Clear();
    }

    #endregion

    /// <summary>
    /// Populates the checkboxes with data from a datarow array. If the array contains an item that matches
    /// the checkbox key, that checkbox will be checked
    /// </summary>
    /// <param name="rows"></param>
    /// <param name="KeyField"></param>
    /// <param name="OtherField"></param>
    public virtual void LoadData(DataTable data, string KeyField, string OtherField)
    {
        this.PreRender += delegate(object sender, EventArgs e)
        {
            if (data != null)
            {
                foreach (DataRow row in data.Rows)
                {
                    string key = string.Empty;

                    if ((System.DBNull.Value.Equals(row[KeyField])) || (row[KeyField].ToString() == "-1"))
                    {
                        key = "Others";
                        txtOtherText.Text = row[OtherField].ToString();
                        tblOtherRow.Style["display"] = "";
                    }
                    else
                    {
                        key = row[KeyField].ToString();
                    }

                    cbxList[key].Checked = true;
                    LoadAdditional(row, key);
                }
            }
        };
    }

    /// <summary>
    /// Used by inheriting classes to do additional stuff while loading
    /// </summary>
    /// <param name="row"></param>
    /// <param name="key"></param>
    protected virtual void LoadAdditional(DataRow row, string key)
    {
    }

    /// <summary>
    /// Clears all data from the CheckBox list and other text field
    /// </summary>
    public virtual void Clear()
    {
        txtOtherText.Text = "";

        foreach (string key in cbxList.Keys)
        {
            cbxList[key].Checked = false;
            ClearAdditional(key);
        }
    }

    /// <summary>
    /// Used by inheriting classes to do additional stuff while clearing
    /// </summary>
    /// <param name="key"></param>
    protected virtual void ClearAdditional(string key)
    {
    }


    /// <summary>
    /// Creates a table where information will be loaded. Override in a child class
    /// to customize the data output
    /// </summary>
    /// <returns></returns>
    protected virtual DataTable CreateTable()
    {
        DataTable tbl = new DataTable();
        tbl.Columns.Add("VendorId");
        tbl.Columns.Add("VendorName");
        return tbl;
    }

    /// <summary>
    /// Creates a row-compatible object where information will be stored. Override in a child class
    /// to customize the data output. Must match the table defined in CreateTable
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    protected virtual object[] GetKeyObject(string key)
    {
        return new object[] 
        { 
            (key == "Others" ? "-1" : key), 
            (key == "Others" ? txtOtherText.Text : null) 
        };
    }


    /// <summary>
    /// Returns a DataTable containing the list of checked items
    /// </summary>
    /// <returns></returns>
    public virtual DataTable GetData()
    {
        DataTable tbl = CreateTable();
        DataRow[] rows = new DataRow[cbxList.Keys.Count];
        foreach (string key in cbxList.Keys)
        {
            GetDataAdditional(key);

            if (cbxList[key].Checked)
            {
                tbl.Rows.Add(GetKeyObject(key));
            }
        }


        return tbl;
    }

    protected virtual void GetDataAdditional(string key)
    {
    }

    protected override void Render(HtmlTextWriter writer)
    {
        // Parepare the control hiearchy for rendering
        // PrepareControlHierarchyForRendering();

        RenderContents(writer);
        //if(Controls.Count>0)
        //    Controls[0].RenderControl(writer);
    }

    protected TableCell CreateCellWithText(string text, Unit width)
    {
        TableCell cell = new TableCell();
        Label lbl = new Label();
        lbl.Text = text;
        lbl.Width = width;
        cell.Controls.Add(lbl);
        return cell;
    }

    protected virtual void CreateControlHierarchy(bool useDataSource)
    {
        Table tbl = new Table();

        tbl.EnableViewState = false;

        // create and add regular checkbox rows
        DataTable srcTable;

        if (useDataSource)
        {
            srcTable = (DataTable)datasource;
        }
        else
        {
            srcTable = (DataTable)ViewState["CheckBoxListOtherData"];
            valuefield = (string)ViewState["ValueField"];
            textfield = (string)ViewState["TextField"];
        }


        foreach (DataRow r in srcTable.Rows)
        {
            tbl.Rows.Add(CreateTableRow(r[valuefield].ToString(), r[textfield].ToString(), r["id"].ToString(), r["onclick"].ToString()));
        }

        // Create the separate hidden row for others
        // Need to create this first (but not add it yet) 
        // so we can reference this row later
        tblOtherRow = CreateTableOtherRow();
        // Create the Other checkbox row and pass the Other textbox row for toggling visibility
        TableRow tblOtherCheckBoxRow = CreateTableRow("Others", sOtherCheckboxText, null, null, tblOtherRow);

        // now add them in the correct order
        tbl.Rows.Add(tblOtherCheckBoxRow);
        tbl.Rows.Add(tblOtherRow);

        tbl.Width = this.Width;

        this.Controls.Add(tbl);

        ViewState["CheckBoxListOtherData"] = srcTable;
        ViewState["ValueField"] = valuefield;
        ViewState["TextField"] = textfield;

        this.PreRender += delegate(object sender, EventArgs args)
        {
            ScriptManager.AddShowHideCheckBoxElement(Page);

            tblOtherRow.Style["display"] = cbxList["Others"].Checked ? "" : "none";
        };

    }

    protected virtual TableRow CreateTableOtherRow()
    {
        // Creates a new table inside a row
        TableRow tblOtherRow = new TableRow();
        TableCell tblOtherCell = new TableCell();

        Table tblOther;
        tblOther = new Table();
        TableRow tblOtherRow1 = new TableRow();
        TableRow tblOtherRow2 = new TableRow();
        tblOtherRow1.CssClass = "bodytext";
        tblOtherRow2.CssClass = "bodytext";

        tblOther.Rows.Add(tblOtherRow1);
        tblOther.Rows.Add(tblOtherRow2);
        tblOtherRow1.Cells.Add(CreateCellWithText(sOtherTextPrompt, 200));

        TableCell tblOtherText = new TableCell();
        txtOtherText.CssClass = "big-textBoxes";
        tblOtherText.Controls.Add(txtOtherText);
        tblOtherRow2.Cells.Add(tblOtherText);

        tblOtherCell.ColumnSpan = 2;
        tblOtherCell.Controls.Add(tblOther);
        tblOtherRow.Cells.Add(tblOtherCell);
        tblOtherRow.Style["display"] = "none";

        return tblOtherRow;
    }

    protected virtual TableRow CreateTableRow(string key, string text)
    {
        return CreateTableRow(key, text, null, null, null);
    }

    protected virtual TableRow CreateTableRow(string key, string text, string id, string onclickevent)
    {
        return CreateTableRow(key, text, id, onclickevent, null);
    }

    protected virtual TableRow CreateTableRow(string key, string text, string id, string onclickevent, TableRow hideControl)
    {
        TableRow tblrow = new TableRow();
        tblrow.CssClass = "bodytext";

        TableCell tblcell1 = new TableCell();

        Table tblUnits = new Table();
        CheckBox cbx = new CheckBox();
        cbx.Attributes.Add("Value", key);
        if(!string.IsNullOrEmpty(id))
            cbx.ID = id;
        cbxList.Add(key, cbx);
        cbx.Text = text;

        if (hideControl != null)
        {
            this.PreRender += delegate(object sender, EventArgs e)
            {
                cbx.Attributes.Add("onclick", "ShowHideElement('" + cbx.ClientID + "', '" + hideControl.ClientID + "')");
            };
        }
        else
        {
            this.PreRender += delegate(object sender, EventArgs e)
            {
                string funcname = cbx.ClientID + "_onclick";
                MatchCollection pids = Regex.Matches(onclickevent, "\\$\\w*");
                foreach (Match pid in pids)
                {
                    onclickevent = onclickevent.Replace(pid.Value, FindControl(pid.Value.Substring(1)).ClientID);
                }

                Page.RegisterStartupScript(funcname, string.Format("<script>function {0}(){{{1}}}</script>", funcname, onclickevent));
                cbx.Attributes.Add("onclick", funcname + "()");
            };
        }

        tblrow.CssClass = "bodytext";

        tblcell1.Controls.Add(cbx);
        tblrow.Cells.Add(tblcell1);

        return tblrow;
    }

}
